package com.db.gffxo.epi.format;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;

import org.apache.log4j.Logger;

import com.db.gffxo.epi.controller.FormatControllerServicesImpl;
import com.db.gffxo.epi.format.type.EventFormatDetails;


public class PropertyConfiguredEventFormatter extends AbstractFormatter {

	private Logger log = Logger.getLogger(FormatControllerServicesImpl.class);

	//Props
	private String formatProperties = null;
	private String curDir = null;
	private HashMap<String,EventFormatDetails> allEvents =  new HashMap<String,EventFormatDetails>();
	private HashMap<String,String> dataDefaults = new HashMap<String,String>();
	
	public PropertyConfiguredEventFormatter() {
		
	}
	
	@Override
	public String formatEvent(String arg1, String arg2) {
		
		if (!(arg1.equals("ASM"))) 
			throw new RuntimeException("InvalidFormatType");
		
		HashMap<String,String>eventData =(HashMap<String,String>) getDataDefaults().clone();
		
		StringTokenizer tk = new StringTokenizer(arg2,",");
		while (tk.hasMoreTokens()){
			String kvPair=tk.nextToken();
			StringTokenizer tk1 = new StringTokenizer(kvPair,"=");
			String key = tk1.nextToken();
			String value = tk1.nextToken();
			eventData.put(key, value);
		}
		
		String asmType = eventData.get("type");
		
		if (asmType==null)
			throw new RuntimeException("InvalidAsmEvent");
		
		EventFormatDetails efd = getAllEvents().get(asmType);
		if (efd==null)
			throw new RuntimeException("AsmTypeNotDefined");
		
		return efd.formatMessage(eventData);
	}
	
	public void configureFormatter(String formatterId) {
		setFormatterId(formatterId);
		loadEventInfo();
	}

	public void loadEventInfo () {
		log.info("Loading property based formats");
		SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
		String today = sd.format(Calendar.getInstance().getTime());
		curDir = System.getProperty("user.dir").concat(System.getProperty("file.separator"));
	

		InputStream fis;
		try {
			Properties props = new Properties();
			fis = this.getClass().getClassLoader().getResourceAsStream(getFormatProperties());

			props.load(fis);
			String eventList = getMandatoryProperty(props,"asm.events");
			
			StringTokenizer tk = new StringTokenizer(eventList,",");

			while (tk.hasMoreTokens()) {
				String eventCode=tk.nextToken();
				String evt = "asm.".concat(eventCode.concat("."));
				EventFormatDetails event = new EventFormatDetails();
				event.setProtocol(getMandatoryProperty(props, evt,"protocol"));
				event.setDeviceVendor(getMandatoryProperty(props, evt,"devicevendor"));
				event.setDeviceProduct(getMandatoryProperty(props, evt,"deviceproduct"));
				event.setDeviceVersion(getMandatoryProperty(props, evt,"deviceversion"));
				event.setPriority(getMandatoryProperty(props, evt,"devicepriority"));
				event.setSignatureId(getMandatoryProperty(props, evt,"signatureid"));
				event.setName(getMandatoryProperty(props, evt,"name"));
				
				event.setMandatoryFields(getMandatoryProperty(props, evt,"mandatory"));
				event.setOptionalFields(getMandatoryProperty(props, evt,"optional"));

				StringTokenizer tk1 = new StringTokenizer(event.getMandatoryFields(),",");
				HashMap<String,String> keyValuePairs = new HashMap<String,String>();
				while (tk1.hasMoreTokens()) {
					String level = evt.concat("mandatory").concat(".");
					String key = tk1.nextToken();
					String value = getMandatoryProperty(props, level, key);
					keyValuePairs.put(key, value);
				}
				event.setManKeyValuePairs(keyValuePairs);

				tk1 = new StringTokenizer(event.getOptionalFields(),",");
				keyValuePairs = new HashMap<String,String>();
				while (tk1.hasMoreTokens()) {
					String level = evt.concat("optional").concat(".");
					String key = tk1.nextToken();
					String value = getMandatoryProperty(props, level, key);
					keyValuePairs.put(key, value);
				}
				event.setOptKeyValuePairs(keyValuePairs);
				
				getAllEvents().put(eventCode, event);
			}

			
			//Store the system wide defaults into a hash map
			String defaults = getMandatoryProperty(props,"asm.defaults");			
			tk = new StringTokenizer(defaults,",");
			while (tk.hasMoreTokens()) {
				String level="asm.defaults.";
				String key = tk.nextToken();
				String value = getMandatoryProperty(props,level,key);
				getDataDefaults().put(key, value);
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MandatoryPropertyException e){
			System.out.println("Missing Property: ".concat(e.getMissingProperty()));
			System.exit(1);
		}
	}

	public String getMandatoryProperty(Properties props, String property) throws MandatoryPropertyException {
		String levels = null;
		return getMandatoryProperty(props,levels,property);
	}
	
	public String getMandatoryProperty(Properties props, String levels, String property) throws MandatoryPropertyException {
		StringBuffer fullProperty= new StringBuffer();
		if (!(levels==null))
			fullProperty.append(levels);
		
		fullProperty.append(property);
		
		String value = props.getProperty(fullProperty.toString());
		if (value == null||value.equals("")) {
			throw (new MandatoryPropertyException(fullProperty.toString()));
		}
		return value;
	}
	
	public String getOptionalProperty(Properties props, String property) {
		String levels = null;
		return getOptionalProperty(props,levels,property);
	}

	public String getOptionalProperty(Properties props, String levels, String property) {
		StringBuffer fullProperty= new StringBuffer();
		if (!(levels==null))
			fullProperty.append(levels);
		
		fullProperty.append(property);
		
		String value = props.getProperty(fullProperty.toString());
		if (value == null) {
			value = "";
		}
		return value;
	}
	
	// Exeptions
	private class MandatoryPropertyException extends Exception {
		//TODO - Migrate to external exception
		private static final long serialVersionUID = 1L;
		String missingProperty;
		
		public MandatoryPropertyException (String prop) {
			super(prop);
			missingProperty = prop;
		}
		
		public String getMissingProperty () {
			return missingProperty;
		}
	}

	// Getters and Setters
	public String getFormatProperties() {
		return formatProperties;
	}

	public void setFormatProperties(String formatProperties) {
		this.formatProperties = formatProperties;
	}

	public String getCurDir() {
		return curDir;
	}

	public void setCurDir(String curDir) {
		this.curDir = curDir;
	}

	public HashMap<String, EventFormatDetails> getAllEvents() {
		return allEvents;
	}

	public void setAllEvents(HashMap<String, EventFormatDetails> allEvents) {
		this.allEvents = allEvents;
	}

	public HashMap<String, String> getDataDefaults() {
		return dataDefaults;
	}

	public void setDataDefaults(HashMap<String, String> dataDefaults) {
		this.dataDefaults = dataDefaults;
	}


}
